#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>      // usleep()
#include <wiringPi.h>
#include <pthread.h>     // 线程库
#include <stdbool.h>     // bool 类型

// --- 宏定义 ---
#define SG90_PIN          1  // 使用 wPi 编号 1, 对应物理引脚 12
#define PWM_PERIOD_US     20000 // PWM 总周期: 20ms = 20000us
#define MIN_PULSE_WIDTH_US 500  // 0  度时对应的脉宽 (0.5ms)
#define MAX_PULSE_WIDTH_US 2500  // 180度时对应的脉宽 (2.5ms)

// --- 线程间共享的数据 ---

// 1. 互斥锁: 用于保护下面的共享变量
pthread_mutex_t servo_lock;

// 2. 目标脉冲宽度 (单位: 微秒)
//    volatile 关键字防止编译器过度优化，确保每次都从内存读取
volatile int g_target_pulse_width_us = 1500; // 默认启动时在90度位置

// 3. 线程运行控制标志
volatile bool g_is_running = true;

// --- 辅助函数：将角度 (0-180) 转换为脉冲宽度 (500-2500us) ---
int angle_to_pulse_width(int angle) {
    // 使用浮点数进行精确的线性映射
    double pulse = MIN_PULSE_WIDTH_US + (angle / 180.0) * (MAX_PULSE_WIDTH_US - MIN_PULSE_WIDTH_US);
    return (int)pulse;
}

// --- PWM子线程函数：只负责生成PWM波形 ---
void *pwm_thread_func(void *argv) {
    int current_pulse_width;

    printf("PWM子线程已启动。\n");

    while (g_is_running) {
        // --- 从共享变量中安全地读取脉宽值 ---
        pthread_mutex_lock(&servo_lock);
        current_pulse_width = g_target_pulse_width_us;
        pthread_mutex_unlock(&servo_lock);

        // --- 生成一个精确的PWM周期 ---
        // 1. 拉高电平
        digitalWrite(SG90_PIN, HIGH);
        // 2. 延时高电平需要持续的时间
        usleep(current_pulse_width);

        // 3. 拉低电平
        digitalWrite(SG90_PIN, LOW);
        // 4. 延时低电平需要持续的时间 (总周期为20000us)
        usleep(PWM_PERIOD_US - current_pulse_width);
    }
    
    printf("PWM子线程已退出。\n");
    return NULL;
}

// --- 主线程：负责初始化、用户交互和清理 ---
int main() {
    pthread_t pwm_thread_id;
    int choice_angle;

    // 初始化 wiringPi
    if (wiringPiSetup() == -1) {
        printf("WiringPi 初始化失败。\n");
        return 1;
    }
    pinMode(SG90_PIN, OUTPUT);
    
    // 初始化互斥锁
    if (pthread_mutex_init(&servo_lock, NULL) != 0) {
        printf("互斥锁初始化失败。\n");
        return 1;
    }

    // 创建并启动PWM子线程
    if (pthread_create(&pwm_thread_id, NULL, pwm_thread_func, NULL) != 0) {
        printf("PWM子线程创建失败。\n");
        return 1;
    }

    // 主循环，等待用户输入
    while (g_is_running) {
        printf("\n请输入舵机角度 (0-180), 或输入 -1 退出: ");
        
        // 检查scanf的返回值，确保成功读取一个整数
        if (scanf("%d", &choice_angle) == 1) {
            if (choice_angle == -1) {
                g_is_running = false; // 通知子线程退出
                printf("程序退出中...\n");
                break; // 跳出主循环
            }
            
            if (choice_angle >= 0 && choice_angle <= 180) {
                // --- 安全地更新共享的脉宽变量 ---
                pthread_mutex_lock(&servo_lock);
                g_target_pulse_width_us = angle_to_pulse_width(choice_angle);
                pthread_mutex_unlock(&servo_lock);
            } else {
                printf("错误：角度超出范围 (0-180)，请重新输入。\n");
            }
        } else {
            printf("错误：无效输入，请输入一个整数。\n");
            // 清空输入缓冲区，防止scanf在遇到非整数输入时无限循环
            while (getchar() != '\n');
        }
    }

    // 等待PWM子线程执行完毕并回收资源
    pthread_join(pwm_thread_id, NULL);
    
    // 销毁互斥锁
    pthread_mutex_destroy(&servo_lock);
    
    // 程序退出前，确保舵机引脚为低电平
    digitalWrite(SG90_PIN, LOW);
    printf("程序已安全退出。\n");

    return 0;
}
